#include <jni.h>
#include <iostream>

#include "ppg/PPG_Algorithm.h"
#include "ppg/PPG_Algorithm_terminate.h"
#include "ppg/coder_array.h"

#define GET(a) ((uint8_t) env->CallByteMethod(env->GetObjectArrayElement(bytes, (a)), byteToInt))

extern "C"
JNIEXPORT jobject JNICALL
Java_com_openwatch_packet_PPGAlgorithms_algorithm(JNIEnv *env, jclass clazz, jobjectArray bytes,
                                                  jint len, jboolean gender, jint age, jdouble prevSpO2) {
    int lengthOfArray = len / 4;

    double array_red[lengthOfArray];
    double array_ir[lengthOfArray];

    jclass byteCls = env->FindClass("java/lang/Byte");
    jmethodID byteToInt = env->GetMethodID(byteCls, "byteValue", "()B");

    for (int i = 0; i < lengthOfArray; ++i) {
        array_red[i] = GET(i * 4) + GET(i * 4 + 1) * 256;
        array_ir[i] = GET(i * 4 + 2) + GET(i * 4 + 3) * 256;
    }

    double PPG_IR[1000], PPG_RED[1000];
    double HR, SpO2;
    int index;
    PPG_Algorithm(array_red, array_ir, gender, age, prevSpO2, &HR, &SpO2, PPG_IR, PPG_RED, &index);

    jdoubleArray result_red = env->NewDoubleArray(lengthOfArray);
    jdoubleArray result_ir = env->NewDoubleArray(lengthOfArray);
    env->SetDoubleArrayRegion(result_red, 0, lengthOfArray, PPG_RED);
    env->SetDoubleArrayRegion(result_ir, 0, lengthOfArray, PPG_IR);

    jclass javaLocalClass = env->FindClass("com/openwatch/packet/PPGData");
    auto javaGlobalClass = reinterpret_cast<jclass>(env->NewGlobalRef(javaLocalClass));
    jmethodID javaConstructor = env->GetMethodID(javaGlobalClass, "<init>", "([D[DDDI)V");
    jobject obj = env->NewObject(javaGlobalClass, javaConstructor, result_red, result_ir, HR, SpO2, index);
    return obj;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_openwatch_packet_PPGAlgorithms_terminate(JNIEnv *env, jclass clazz) {
    PPG_Algorithm_terminate();
}

extern "C"
JNIEXPORT jobject JNICALL
Java_com_openwatch_packet_PPGAlgorithms_test(JNIEnv *env, jclass clazz,
                                             jboolean gender, jint age) {
    double raw_sig_IR[] = {53307,53563,53563,53819,53819,53819,53819,53819,53819,53819,53819,54075,54075,54075,54075,54075,54075,54331,54331,54075,54331,54331,54331,54331,54331,54587,54587,54587,53563,54843,54843,54843,54843,54843,54587,54587,54331,54075,53819,53819,53563,53307,53051,52795,52795,52795,52795,52539,52539,52539,52539,52539,52539,52539,52539,52539,52795,52795,52795,52795,53563,53563,53819,53819,54075,53819,54075,54075,54075,54075,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54331,54587,54587,54331,54587,54587,54587,54587,54075,54843,54843,54843,54843,54843,54843,54843,54843,54587,54587,54843,54843,54587,54843,54843,54587,54843,54587,54843,54843,54843,54843,54843,54843,54843,54587,54587,54587,52539,52283,52027,54075,52027,52027,52283,52283,52283,52283,52539,52539,52539,52539,52539,52795,52795,52795,53051,53051,53051,53051,53051,53051,53307,53307,53307,53307,53307,53307,53307,53563,53307,53563,53563,53307,53307,53307,53563,53307,53563,53563,53563,53563,53563,53307,53563,53563,53563,53563,53563,53563,53563,53563,53563,53563,53563,53563,53819,53563,53563,53819,53819,53819,53819,53819,53819,53819,53819,53819,53819,53819,54075,53819,53563,54075,54075,54075,54075,54075,54075,53819,53819,53819,53819,53563,53307,53307,53051,52795,52539,52283,52283,52027,52027,51771,51771,51771,51771,51515,51515,51515,51515,52027,52283,53819,52283,52283,54075,52539,52539,52539,52795,52795,52795,52795,52795,53051,53051,53051,53051,53307,53051,53307,53307,53307,53307,53307,53307,53307,53051,53307,53307,53307,53307,53051,53051,53051,53051,53051,53051,53051,53307,53307,53051,53307,53307,53307,53307,53307,53307,53307,53563,53563,53563,53563,53563,53563,53563,53563,53563,53563,53819,53819,53819,53819,53819,53819,53819,53819,53819,53819,52539,52539,52027,53307,51771,51515,51515,51259,51259,51259,51259,51259,51003,51003,51003,51003,51003,51259,51259,51259,51259,51259,51515,51515,51515,51771,51771,51771,51771,51771,52027,52027,52539,52795,52027,52539,52795,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52795,52539,52539,52795,52795,52795,52795,53051,53051,53051,53051,53307,53307,53307,53307,53307,53307,53307,53307,53307,53563,53563,53307,53563,53307,53307,53563,53307,53307,53307,53051,53051,52539,52539,52283,52027,51771,51515,51259,51003,50747,50747,53051,51003,51003,51259,51259,51259,51259,51515,51515,51515,51515,51771,51771,51771,51771,52027,52027,52027,52283,52283,52283,52283,52283,52283,52283,52283,52283,52283,52283,52283,52283,50747,52283,52283,52283,52283,52539,52539,52539,52539,52539,52539,52539,52539,52539,52795,52795,52795,52795,52795,52795,53051,53051,53051,53051,53307,53051,53307,53307,53307,53307,53563,53563,53819,53563,53563,53563,53563,53307,53307,53051,52795,52539,52283,52283,52027,51771,51515,51259,51259,51259,51003,51003,51003,51003,51003,51003,51003,51003,51003,51003,51003,51259,51771,52027,52027,52027,53563,52283,52283,52283,52283,52283,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52539,52795,52539,52539,52795,52795,53051,53051,53051,53307,53307,53051,53307,53307,53307,53307,53307,53307,53307,53307,53307,53307,53307,53307,53307,53307,53051,53051,52795,52539,52283,52027,51771,51515,51515,51003,51003,50747,50491,50491,50491,50235,50235,50491,50487,50487,50487,50231,50231,50487,50487,50487,50743,50743,50743,50999,50999,50999,50999,50999,51255,51255,51255,51255,51511,51511,51511,51767,51767,51767,51767,51767,51767,52023,52023,52023,52023,52023,52023,52023,52023,51767,52023,52023,51767,51767,52023,52023,52023,52023,52023,52023,52023,52279,52279,52279,52279,52279,52279,52535,52279,52535,52535,52535,52535,52791,53559,53559,52023,53559,53559,53559,53559,53815,53815,53815,53815,53815,53815,53559,53559,53303,53047,52791,52535,52279,52023,52023,51767,51511,51511,51255,51255,51255,51255,51255,51255,51255,52023,53559,52279,52023,52023,52279,52279,52279,52535,52535,52535,52535,52791,52791,52791,52791,
                          52791,52791,53047,53047,53047,53047,53047,53047,53047,53047,53047,53047,52791,53047,52791,53047,53047,53047,52791,53047,53047,53303,53303,53047,53303,53047,53303,53303,53303,53303,53303,53559,53559,53559,53559,53815,53559,53815,53559,53559,53815,53815,53815,53815,53815,54071,53815,54071,54071,54071,54071,54071,54071,53559,53303,53303,53303,52535,52279,52023,51767,51511,51511,51511,51255,51255,51255,51255,51255,51255,51255,51255,51255,51255,51511,51511,51511,51511,51511,51767,51767,51767,51767,52023,52023,52535,53303,52535,52535,52535,52535,52791,52791,52791,52791,52535,52535,52535,52791,52535,52535,52535,52535,52535,52535,52535,52535,52535,52535,52535,52535,52535,52535,52791,52791,52791,52791,53303,53303,53303,53303,53303,53303,53559,53559,53559,53559,53559,53559,53815,53815,53815,53815,53815,53815,53815,53815,53815,53815,53815,54071,54071,54071,54071,54071,54071,54071,54071,54071,51767,51511,51255,53303,50999,50999,50999,50999,50999,50999,50999,50999,50999,50999,50999,51255,51255,51255,51511,51511,51511,51511,51511,51767,51767,51767,52023,52023,52023,52279,52279,52279,52791,51511,52791,52535,52535,52791,52535,52535,52535,52535,52535,52791,52535,52535,52535,52535,52535,52535,52535,52791,52791,52791,52791,52791,52791,52791,52791,53047,53047,53047,53047,53303,53815,53815,53815,54071,54071,53815,54071,54071,54071,54071,54071,54071,54071,54071,54327,54327,54327,54327,54327,54327,54583,54327,54583,54583,54583,54583,54583,54583,54583,54583,54327,54327,52023,51767,51767,51767,51767,51511,51511,51511,51767,51767,54071,52023,52023,52023,52023,52279,52279,52279,52279,52535,52535,52535,52791,52535,52791,52791,52791,52791,53047,53047,52791,53047,52791,53047,53047,52791,52791,52791,52791,52791,52791,52535,52535,52535,52791,52791,52791,52535,52535,52535,52535,52535,52535,52535,52535,52535,52791,52791,52791,52791,52791,52791,52791,52791,52791,53047,53047,53047,53047,53047,53303,53303,53303,53303,53303};

    double PPG_IR[1000], PPG_RED[1000];
    double HR, SpO2;
    int index;
    PPG_Algorithm(raw_sig_IR, raw_sig_IR, gender, age, 0, &HR, &SpO2, PPG_IR, PPG_RED, &index);

    jdoubleArray result_red = env->NewDoubleArray(1000);
    jdoubleArray result_ir = env->NewDoubleArray(1000);
    env->SetDoubleArrayRegion(result_red, 0, 1000, PPG_RED);
    env->SetDoubleArrayRegion(result_ir, 0, 1000, PPG_IR);

    jclass javaLocalClass = env->FindClass("com/openwatch/packet/PPGData");
    auto javaGlobalClass = reinterpret_cast<jclass>(env->NewGlobalRef(javaLocalClass));
    jmethodID javaConstructor = env->GetMethodID(javaGlobalClass, "<init>", "([D[DDDI)V");
    jobject obj = env->NewObject(javaGlobalClass, javaConstructor, result_red, result_ir, HR, SpO2, index);
    return obj;
}